package com.liy.cjs.commmons.utils;


import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.liy.cjs.commmons.enums.ResponseCodeEnum;
import com.liy.cjs.commmons.exception.TokenAuthenticationException;


import java.util.Date;
import java.util.HashMap;
import java.util.Map;


/**
 *
 *
 *
 */
public class JWTUtil {

    public static final long TOKEN_EXPIRE_TIME = 7200 * 1000;


    // n. 发行人
    private static final String ISSUER = "liy";


    /**
     * 生成Token
     * @param username 用户标识（不一定是用户名，有可能是用户ID 或 者手机号什么的）
     * @param secretKey
     * @return
     */
    public static String generateToken(String username, String secretKey) {

        Algorithm algorithm = Algorithm.HMAC256(secretKey);
        Date now = new Date();
        Date expireTime = new Date(now.getTime() + TOKEN_EXPIRE_TIME);

        // 添加额外信息
        Map<String, String> claimMap = new HashMap();
        claimMap.put("username", username);
        claimMap.put("role","admin");
        claimMap.put("age","18");


//        String token = JWT.create()
//                .withIssuer(ISSUER)
//                .withIssuedAt(now)
//                .withExpiresAt(expireTime)
//                .withClaim("userInfo", claimMap)   // 添加额外信息
//                .sign(algorithm);
//


        JWTCreator.Builder builder = JWT.create()
                .withIssuer(ISSUER)
                .withIssuedAt(now)
                .withExpiresAt(expireTime);

        // 遍历添加 Claim 额外信息
        claimMap.forEach( (key,value) ->
                builder.withClaim(key,value)
        );

        // 生成 token
        String token = builder.sign(algorithm);
        return token;
    }

    /**
     * 校验Token
     * @param token
     * @param secretKey
     * @return
     */
    public static void verifyToken(String token, String secretKey) {
        try {

            Algorithm algorithm = Algorithm.HMAC256(secretKey);

            JWTVerifier jwtVerifier = JWT.require(algorithm).withIssuer(ISSUER).build();

            jwtVerifier.verify(token); // 没有抛出异常 则验证成功

        } catch (JWTDecodeException jwtDecodeException) {
            throw new TokenAuthenticationException(ResponseCodeEnum.TOKEN_INVALID.getCode(), ResponseCodeEnum.TOKEN_INVALID.getMessage());
        } catch (SignatureVerificationException signatureVerificationException) {
            throw new TokenAuthenticationException(ResponseCodeEnum.TOKEN_SIGNATURE_INVALID.getCode(), ResponseCodeEnum.TOKEN_SIGNATURE_INVALID.getMessage());
        } catch (TokenExpiredException tokenExpiredException) {
            throw new TokenAuthenticationException(ResponseCodeEnum.TOKEN_EXPIRED.getCode(), ResponseCodeEnum.TOKEN_INVALID.getMessage());
        } catch (Exception ex) {
            int code = ResponseCodeEnum.UNKNOWN_ERROR.getCode();
            String message = ResponseCodeEnum.UNKNOWN_ERROR.getMessage();
            throw new TokenAuthenticationException(code, message);
        }
    }


//    public static String getUserInfo(String token) {
//
//        DecodedJWT decodedJWT = JWT.decode(token);
//
//        String userInfo = decodedJWT.getClaim("userInfo").asString();
//
//        return userInfo;
//    }


    /**
     * 从Token中提取用户信息
     *
     *
     */
    public static Map<String, String> getUserInfo(String token) {

        Map<String, Claim> claimMap;  // Claim   n. 声称；（财产等）所有权；（向公司等）索赔；专利新特征申明

        try {

            // JWT 解析器,解码器
            DecodedJWT decodedJWT = JWT.decode(token);

            // 解析 数据
            claimMap = decodedJWT.getClaims();  // 得到 Claim 集合

        } catch (Exception e) {
            throw new  RuntimeException("token 校验失败");
        }

        // 返回的数据 map
        Map<String, String> resultMap = new HashMap(claimMap.size());

        for (Map.Entry<String, Claim> entry : claimMap.entrySet()) {
            String k = entry.getKey();
            Claim v = entry.getValue();
            resultMap.put(k, v.asString());
        }

        return resultMap;
    }
}